package ei

import "strconv"

type charType int

const (
	CHAR_TYPE_ANY              charType = 0
	CHAR_TYPE_NUMBER_DIGIT     charType = 1  // 阿拉伯数字
	CHAR_TYPE_NUMBER_CYCLE     charType = 2  // 加圈数字
	CHAR_TYPE_NUMBER_PARE      charType = 3  // 圆括号数字
	CHAR_TYPE_NUMBER_POINT     charType = 4  // 数字点
	CHAR_TYPE_NUMBER_CYCLE_BLA charType = 8  // 黑色加圈数字（11-20）
	CHAR_TYPE_NUMBER_CYCLE_DOU charType = 9  // 加双圈数字
	CHAR_TYPE_LETTER_PARE      charType = 5  // 圆括号字母
	CHAR_TYPE_LETTER_CYCLE_A   charType = 6  // 加圈字母（大写）
	CHAR_TYPE_LETTER_CYCLE_a   charType = 7  // 加圈字母（小写）
	CHAR_TYPE_LETTER_A         charType = 10 // 大写字母
	CHAR_TYPE_LETTER_a         charType = 11 // 小写字母
	CHAR_TYPE_LATIN            charType = 12 // 拉丁文拓展A(拼音字符)
	CHAR_TYPE_PHONETIC         charType = 13 // 音标
	CHAR_TYPE_SYMBOL           charType = 14 // 运算符
	CHAR_TYPE_SPACE            charType = 15 // 空格
	CHAR_TYPE_CTRL             charType = 16 // 控制字符
	CHAR_TYPE_CHINESE			charType = 17 // 中文字符
)

func getCharType(r rune) charType {
	if (r >= 0x2460 && r <= 0x2473) || r == 0x24EA {
		return CHAR_TYPE_NUMBER_CYCLE
	} else if r >= 0x2474 && r <= 0x2487 {
		return CHAR_TYPE_NUMBER_PARE
	} else if r >= 0x2488 && r <= 0x249B {
		return CHAR_TYPE_NUMBER_POINT
	} else if r >= 0x249C && r <= 0x24B5 {
		return CHAR_TYPE_LETTER_PARE
	} else if r >= 0x24B6 && r <= 0x24CF {
		return CHAR_TYPE_LETTER_CYCLE_A
	} else if r >= 0x24D0 && r <= 0x24E9 {
		return CHAR_TYPE_LETTER_CYCLE_a
	} else if (r >= 0x24EB && r <= 0x24F4) || r == 0x24FF {
		return CHAR_TYPE_NUMBER_CYCLE_BLA
	} else if r >= 0x24F5 && r <= 0x24FE {
		return CHAR_TYPE_NUMBER_CYCLE_DOU
	} else if r >= 0x0030 && r <= 0x0039 {
		return CHAR_TYPE_NUMBER_DIGIT
	} else if r >= 0x0041 && r <= 0x005A {
		return CHAR_TYPE_LETTER_A
	} else if r >= 0x0061 && r <= 0x007A {
		return CHAR_TYPE_LETTER_a
	} else if r >= 0xC0 && r <= 0x24F {
		return CHAR_TYPE_LATIN
	} else if r >= 0x250 && r <= 0x2AF {
		return CHAR_TYPE_PHONETIC
	} else if (r >= 0x0021 && r <= 0x002F) || (r >= 0x3A && r <= 0x40) || (r >= 0x005B && r <= 0x0060) {
		return CHAR_TYPE_SYMBOL
	} else if r == 0x0020 {
		return CHAR_TYPE_SPACE
	} else if (r >= 0x0 && r <= 0x001F) || (r >= 0x0080 && r <= 0x009F) {
		return CHAR_TYPE_CTRL
	} else if r >= 0x4E00 && r <= 0x9FBF {
		return CHAR_TYPE_CHINESE
	} else {
		return CHAR_TYPE_ANY
	}
}

type readState int

const (
	is_any    readState = 0
	is_number readState = 1
	is_txt    readState = 2
	is_symbol readState = 3
	is_para_S readState = 4 // 括号开始
	is_para_E readState = 5 // 括号结束
	is_str    readState = 6 // 引号包括的字符串
)

var defFixSymbol [][]rune = [][]rune{[]rune("["), []rune("]"), }
func char2Token(str []rune, fixSymbol [][]rune) []Token {
	var readState = is_any
	var charTmp string
	var tokens []Token
	var strChar string // 包裹字符串的符号(单引号，双引号，中文等)
	for i := 0; i < len(str); i++ {
		char := str[i]
		// 在任何情况下，下面条件直接添加tokens
		if (char == 0x0028 && readState != is_number) || char == 0x0029 { // 左右括号, number会在下面处理的时候加乘号
			appendToken(&tokens, createTokenFromState(readState, charTmp),
				Token{TypeClass: TYPE_SYMBOL, Value: string(char)})
			charTmp = ""
			readState = is_any
			continue
		} else if char == rune('?') {
			appendToken(&tokens, createTokenFromState(readState, charTmp),
				Token{TypeClass: TYPE_TAGET, Value: string(char)})
			charTmp = ""
			readState = is_any
			continue
		} else if char == rune('"') || char == rune('\'') || char == rune('`') {
			if readState == is_str {
				if string(char) == strChar {
					appendToken(&tokens, createTokenFromState(readState, charTmp))
					charTmp = ""
					readState = is_any
				} else {
					charTmp += string(char)
				}
			} else {
				appendToken(&tokens, createTokenFromState(readState, charTmp))
				charTmp = ""
				strChar = string(char)
				readState = is_str
			}
			continue
		} else if char == rune(' '){
			if readState == is_str {
				// 留空，不进行任何操作
			} else {
				appendToken(&tokens, createTokenFromState(readState, charTmp))
				charTmp = ""
				readState = is_any
				continue
			}
		} else {
			var found []rune
			FixSymobFindingLoop:for _, fix := range fixSymbol{
				for count, r := range fix{
					if str[i + count] != r {
						continue FixSymobFindingLoop
					}
					if len(fix) > len(found) {
						found = fix
					}
				}
			}
			if len(found) > 0 {
				appendToken(&tokens, createTokenFromState(readState, charTmp),
					Token{TypeClass:TYPE_SYMBOL, Value:string(found)})
				charTmp = ""
				readState = is_any
				continue
			}
		}
		// 根据解析状态，做相应操作
		switch readState {
		case is_any:
			readState = getNewState(char, readState)
			charTmp += string(char)
		case is_number:
			if getNewState(char, readState) == is_number || char == 0x002E {
				charTmp += string(char)
			} else if getNewState(char, readState) == is_txt {
				appendToken(&tokens,
					createTokenFromState(readState, charTmp),
					Token{TypeClass: TYPE_SYMBOL, Value: "*"})
				charTmp = string(char)
				readState = is_txt
			} else if char == 0x0028 { // 左括号
				appendToken(&tokens,
					createTokenFromState(readState, charTmp),
					Token{TypeClass: TYPE_SYMBOL, Value: "*"},
					Token{TypeClass: TYPE_SYMBOL, Value: "("})
				charTmp = ""
				readState = is_any
			} else {
				appendToken(&tokens, createTokenFromState(readState, charTmp))
				readState = getNewState(char, readState)
				charTmp = string(char)
			}
		case is_txt:
			if getNewState(char, readState) == is_txt || getNewState(char, readState) == is_number {
				charTmp += string(char)
			} else {
				appendToken(&tokens, createTokenFromState(readState, charTmp))
				readState = getNewState(char, readState)
				charTmp = string(char)
			}
		case is_symbol:
			if getNewState(char, readState) == is_symbol {
				charTmp += string(char)
			} else {
				appendToken(&tokens, createTokenFromState(readState, charTmp))
				readState = getNewState(char, readState)
				charTmp = string(char)
			}
		case is_str:
			charTmp += string(char)
		}
	}
	appendToken(&tokens, createTokenFromState(readState, charTmp))
	for _, v := range tokens {
		v.Print()
	}
	return tokens
}

func getNewState(rStr rune, oldState readState) readState {
	switch getCharType(rStr) {
	case CHAR_TYPE_NUMBER_DIGIT:
		return is_number
	case CHAR_TYPE_SYMBOL:
		if rStr == rune('_') {
			return is_txt
		} else {
			return is_symbol
		}
	case CHAR_TYPE_LETTER_A, CHAR_TYPE_LETTER_a, CHAR_TYPE_CHINESE:
		return is_txt
	case CHAR_TYPE_CTRL:
		return is_any
	case CHAR_TYPE_SPACE: // 在循环中直接跳过，否则空格会加到Token中
		return oldState
	default:
		panic("无法识别字符")
	}
}

func createTokenFromState(state readState, str string) Token {
	if str == "" || str == "\n" {
		return SpcToken()
	}
	switch state {
	case is_number:
		v, err := strconv.ParseFloat(str, 64)
		if err != nil {
			panic(err)
		} else {
			return Token{TypeClass: TYPE_FLOAT, Value: v}
		}
	case is_txt:
		return Token{TypeClass: TYPE_TXT, Value: str}
	case is_symbol:
		return Token{TypeClass: TYPE_SYMBOL, Value: str}
	case is_str:
		return Token{TypeClass: TYPE_STRING, Value: str}
	default:
		panic("无法识别Token类型(createTokenFromState)" + strconv.Itoa(int(state)) + str)
	}
}

func appendToken(token *[]Token, item ...Token) {
	for i := 0; i < len(item); i++ {
		if item[i].TypeClass != TYPE_SPC {
			*token = append(*token, item[i])
		}
	}
}
func handleTokenGroup(tokens *[]Token, handle func(t *[]Token)) {
	handle(tokens)
	for i := 0; i < len(*tokens); i++ {
		if (*tokens)[i].TypeClass == TYPE_LIST || (*tokens)[i].TypeClass == TYPE_ARGS {
			tmp := (*tokens)[i].Value.([]Token)
			handleTokenGroup(&tmp, handle)
			(*tokens)[i].Value = tmp
		}
	}
	return
}
